`include "../codigo/Memory.v"


module t_Memory;

	reg clock;
	reg reset;

    // Execute
	reg [2:0] ex_mem_msm;
	reg [2:0] ex_mem_msl;
	reg ex_mem_readmem;
	reg ex_mem_writemem;
	reg ex_mem_mshw;
	reg ex_mem_lshw;
	reg [31:0] ex_mem_regb;
	reg [2:0] ex_mem_selwsource;
	reg [4:0] ex_mem_regdest;
	reg ex_mem_writereg;
	reg [31:0] ex_mem_aluout;
	reg [31:0] ex_mem_wbvalue;

    // Memory Controller
	wire mem_mc_rw;
	wire mem_mc_en;
	wire [31:0]	mem_mc_addr;
	wire [31:0]	mem_mc_data;
	wire mem_mc_mshw;
	wire mem_mc_lshw;

    // Forwarding
	wire [31:0] mem_fw_wbvalue;
	wire mem_fw_writereg;

    //  Writeback
	wire [4:0] mem_wb_regdest;
	wire mem_wb_writereg;
	wire [31:0] mem_wb_wbvalue;


    Memory memory(
        clock,
        reset,
        ex_mem_msm,
        ex_mem_msl,
        ex_mem_readmem,
        ex_mem_writemem,
        ex_mem_mshw,
        ex_mem_lshw,
        ex_mem_regb,
        ex_mem_selwsource,
        ex_mem_regdest,
        ex_mem_writereg,
        ex_mem_aluout,
        ex_mem_wbvalue,
        mem_mc_rw,
        mem_mc_en,
        mem_mc_addr,
        mem_mc_data,
        mem_mc_mshw,
        mem_mc_lshw,
        mem_fw_wbvalue,
        mem_fw_writereg,
        mem_wb_regdest,
        mem_wb_writereg,
        mem_wb_wbvalue
    );

    

    // Calls up the tasks
    initial begin

        clock = #0 0;

        // Reset
        test_reset();

        // Load
        test_load();

        // Store
        test_store();

        // Load
        test_load();

        $finish;

    end

    // Clock
    always begin
        #5 clock = ~clock;
    end


    // --------------------------------------------------------------
    // Tests reset
    task test_reset;
    begin

        $display();
        reset = #0 0;
        #5;
        $display(" -----------------------------------------------");
        $display(" >>> Reset:");
        $display(" Exibe o valor dos sinais que sao enviados");
        $display(" ao estagio de escrita quando ocorre reset.\n");
        $display(" - Reset: %b;", reset);
        print_memory_write();

        $display();
        reset = #0 1;
        #5;
        $display(" - Reset: %b;", reset);
        print_memory_write();
        $display();

    end
    endtask


    // Prints execute_mem signs
    task print_memory_write;
    begin

        $display(" ex_mem_regdest: %b;", ex_mem_regdest);
        $display(" ex_mem_writereg: %b;", ex_mem_writereg);
        $display(" ex_mem_wbvalue: %b;", ex_mem_wbvalue);
        $display(" mem_wb_regdest: %b;", mem_wb_regdest);
        $display(" mem_wb_writereg: %b;", mem_wb_writereg);

    end
    endtask
   
    
    // --------------------------------------------------------------
    // Tests memory load 
    task test_load; begin

        $display();
        $display(" -----------------------------------------------");
        $display(" >>> Load:");
        $display(" Testa o load de informacoes a partir da analise");
        $display(" do barramento que conecta o modulo");
        $display(" de execucao ao modulo de forward.");
        
        ex_mem_msm = #0 3'b1;
        ex_mem_msl = #0 3'b10;
        ex_mem_readmem = #0 1;
        ex_mem_aluout = #0 32'b100000;

        #10;
        print_load();
        $display();

        #5;
        ex_mem_readmem = #0 0;

    end
    endtask

    // Prints the writeback data
    task print_load; begin

        $display(" - Load data:");
        $display(" ex_mem_msm: %b;", ex_mem_msm);
        $display(" ex_mem_msl: %b;", ex_mem_msl);
        $display(" ex_mem_readmem: %b;", ex_mem_readmem);
        $display(" ex_mem_aluout: %b;", ex_mem_aluout);
        $display(" mem_mc_rw: %b;", mem_mc_rw);
        $display(" mem_mc_en: %b;", mem_mc_en);
        $display(" mem_mc_addr: %b;", mem_mc_addr);
        $display(" mux_loadregb: %b;", memory.mux_loadregb);
        $display(" loadval: %b;", memory.loadval);

    end
    endtask



    // --------------------------------------------------------------
    // Tests memory store
    task test_store; begin

        $display();
        $display(" -----------------------------------------------");
        $display(" >>> Store:");
        $display(" Testa operacoes de store na memoria, analisando");
        $display(" o resultado obtido a partir do load do dado");
        $display(" recem escrito.");

        ex_mem_msm = #0 3'b01;
        ex_mem_msl = #0 3'b1;
        ex_mem_writemem = #0 1;
        ex_mem_aluout = #0 32'b100000;

        #10;
        print_store();        
        $display();

        #5;
        ex_mem_writemem = #0 0;

    end
    endtask

    // Prints the writeback data
    task print_store; begin

        $display(" - Store data:");
        $display(" ex_mem_msm: %b;", ex_mem_msm);
        $display(" ex_mem_msl: %b;", ex_mem_msl);
        $display(" ex_mem_readmem: %b;", ex_mem_readmem);
        $display(" ex_mem_aluout: %b;", ex_mem_aluout);
        $display(" mem_mc_rw: %b;", mem_mc_rw);
        $display(" mem_mc_en: %b;", mem_mc_en);
        $display(" mem_mc_addr: %b;", mem_mc_addr);
        $display(" mux_loadregb: %b;", memory.mux_loadregb);
        $display(" loadval: %b;", memory.loadval);

    end
    endtask


endmodule
